<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\Common\Constants\StatusConstants;
use App\Common\Interfaces\ProxyIpInterface;
use App\Common\Model\Region;
use App\Common\Robot\Robot;
use App\CustHub\Constants\RobotLoginTypeConstants;
use App\CustHub\Dto\RobotLoginAfterDto;
use App\CustHub\Event\RobotInfoChange;
use App\CustHub\Event\RobotLoginAfter;
use App\CustHub\Mapper\ChCorpMapper;
use App\CustHub\Mapper\ChRobotMapper;
use App\CustHub\Mapper\ChSeatMapper;
use App\CustHub\Model\ChRobot;
use App\CustHub\Model\ChSeat;
use App\Robot\Dto\CommonJobDto;
use App\Robot\Job\CommonJob;
use App\Robot\Job\UserIdToOpenIdTaskJob;
use App\Robot\Service\RobotApiService;
use Carbon\Carbon;
use FriendsOfHyperf\Lock\Exception\LockTimeoutException;
use Hyperf\Database\Model\Builder;
use Hyperf\Database\Model\Model;
use Hyperf\Di\Annotation\Inject;
use Mine\Annotation\Transaction;
use Mine\Exception\NormalStatusException;
use Mine\Helper\Str;
use Mine\MineModel;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\EventDispatcher\EventDispatcherInterface;
use function FriendsOfHyperf\Lock\lock;
use function Hyperf\Collection\data_get;
use function Hyperf\Support\optional;

class RobotLoginService
{
    #[Inject]
    protected ChRobotMapper $robotMapper;

    #[Inject]
    protected ChSeatMapper $seatMapper;

    #[Inject]
    protected EventDispatcherInterface $eventDispatcher;

    #[Inject]
    protected ChServerService $serverService;

    #[Inject]
    protected ProxyIpInterface $proxyIpService;


    protected const ROBOT_LOGIN_KEY = 'ch_robot_login_check:';

    /**
     * 获取登录二维码
     * @param array $params
     * @return array
     */
    public function getLoginQrCode(array $params): array
    {
        $robotId = data_get($params,'robot_id');
        $proCode = data_get($params,'pro_code','');
        $cityCode = data_get($params,'city_code','');

        $key = '';
        $isYd = false;
        $msg = '';
        $proxyUrl = '';
        if(!empty($robotId)){
            $robotInfo = $this->robotMapper->findById($robotId);
            if($robotInfo['login_status'] == StatusConstants::ENABLE){
                throw new NormalStatusException('当前在线，请先退出登录');
            }

            if(empty($robotInfo->seat_id) && !$this->seatMapper->checkIsAvailSeatExist($params['main_uid'])){
                $remark = '账户席位不足，请购买席位后重试~';
                throw new NormalStatusException($remark);
            }

            $serverId = $robotInfo->server_id;
            $server = $this->serverService->findById($serverId);
            if($server->city_code != $cityCode || $server->pro_code != $proCode){
                $isYd = true;
                $msg = '您所选地区无可用服务器,请联系客服进行分配。';
            }
            empty($proCode) && $proCode = $robotInfo->pro_code;
            empty($cityCode) && $cityCode = $robotInfo->city_code;
            if(empty($robotInfo->uuid)){
                $uuid = \Hyperf\Stringable\Str::uuid()->toString();
            }else{
                $uuid = $robotInfo->uuid;
            }
        }else{
            if(!$this->seatMapper->checkIsAvailSeatExist($params['main_uid'])){
                $remark = '账户席位不足，请购买席位后重试~';
                throw new NormalStatusException($remark);
            }

            $server = $this->serverService->getServerByIp($proCode,$cityCode);
            if(empty($server)){
                throw new NormalStatusException('暂无可用服务器，请联系管理员~');
            }
            $serverId = $server['id'];
            $isYd = $server->isYd;
            $msg = $isYd ? '您所选地区无可用服务器,请联系客服进行分配。' : '';
            $uuid = \Hyperf\Stringable\Str::uuid()->toString();
        }

        if($isYd){
            //异地登录获取代理地址
            $proxyUrl = $this->proxyIpService->getShortProxyIp($proCode,$cityCode);
        }

        $robotApiService = make(Robot::class,[$serverId,$uuid])->gateway();
        $customerParam = $params['main_uid']."_".$serverId;

        if(!empty($proCode) && !empty($cityCode)){
            $customerParam = $customerParam.'_'.$proCode.'_'.$cityCode;
        }

        $response = $robotApiService->getLoginQrCode($customerParam,$proxyUrl);
        if($response === false){
            throw new NormalStatusException('获取二维码失败，请重试~');
        }

        $result['is_yd'] = $isYd;
        $result['msg'] = $msg;
        $result['loginQrcodeBase64Data'] = $response['login_qrcode_base64_data'];
        $result['loginQrcodeKey'] = $response['login_qrcode_key'];
        $key = self::ROBOT_LOGIN_KEY.$result['loginQrcodeKey'];

        redis()->set($key,[
            'server_id' => $serverId,
            'uuid' => $uuid,
            'pro_code' => $proCode,
            'city_code' => $cityCode
        ],60 * 60);
        return $result;
    }

    /**
     * 验证登录
     * @param array $params
     * @return array|mixed
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * @throws \RedisException
     */
    public function verifyLogin(array $params): mixed
    {
        $loginData =  redis()->get(self::ROBOT_LOGIN_KEY.$params['loginQrcodeKey']);
        if(empty($loginData)){
            throw new NormalStatusException("请先扫码");
        }
        $serverId = $loginData['server_id'];
        $uuid = $loginData['uuid'];

        $robotApiService = make(Robot::class,[$serverId,$uuid])->gateway();
        $response = $robotApiService
            ->verifyLoginQrcode($params['verifyCode'],$params['loginQrcodeKey']);
        if($response === false){
            throw new NormalStatusException($robotApiService->getErrorMsg());
        }
        return $response;
    }


    /**
     * 机器人登录检查 返回登录状态
     * @param array $params
     * @return int|mixed
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * @throws \RedisException
     */
    #[Transaction]
    public function robotLogin(array $params): mixed
    {
        $mainUid = $params['main_uid'];
        $loginQrcodeKey = $params['loginQrcodeKey'];
        $lock = lock('robot_login_lock:'.$mainUid, 10);
        $loginStatus = 0;
        try {
            $lock->block(5);
            $checkKey = self::ROBOT_LOGIN_KEY.$loginQrcodeKey;
            $loginData =  redis()->get($checkKey);
            if($loginData){
                $serverId = $loginData['server_id'];
                $serverInfo = $this->serverService->findById($serverId);
                if($serverInfo->gateway == 'winWeWork'){
                    return $this->winRobotLogin($params);
                }
                $uuid = $loginData['uuid'];

                $robotApiService = make(Robot::class,[$serverId,$uuid])->gateway();
                $response = $robotApiService->checkLoginQrCode();
                if($response !== false){
                    $loginStatus = $response['login_qrcode_status'];
                    if($loginStatus == -1){
                        $loginStatus = 0;
                    }
                    if($loginStatus == 2){
                        //登录成功
                        //所在省份编码
                        $proCode = $loginData['pro_code'];
                        //所在城市编码
                        $cityCode = $loginData['city_code'];


                        $isYd = 0;
                        if($serverInfo->pro_code != $proCode || $serverInfo->city_code != $cityCode){
                            $isYd = 1;
                        }

                        $regionCode = array_unique(array_filter([$serverInfo->pro_code,$serverInfo->city_code,$proCode,$cityCode]));
                        $regionNameMap = Region::query()
                            ->whereIn('code',$regionCode)
                            ->pluck('name','code')
                            ->toArray();
                        $proName = '';
                        $cityName = '';
                        if(!empty($proCode)){
                            $proName = $regionNameMap[$proCode] ?? '';
                        }
                        if(!empty($cityCode)){
                            $cityName = $regionNameMap[$cityCode] ?? '';
                        }
                        $serverProName = $regionNameMap[$serverInfo->pro_code] ?? '';
                        $serverCityName = $regionNameMap[$serverInfo->city_code] ?? '';

                        $robotInfo = $this->robotMapper->model::query()
                            ->withTrashed()
                            ->where('main_uid',$mainUid)
                            ->where('user_id',$response['user_id'])
                            ->first();
                        if(empty($robotInfo) || empty($robotInfo->seat_id)){
                            //机器人登录成功
                            $seat = $this->getAvailableSeats($mainUid);
                            if(empty($seat)){
                                $remark = '账户席位不足，请购买席位后重试~';
                                if(!empty($robotInfo)){
                                    $this->eventDispatcher->dispatch(new RobotLoginAfter(new RobotLoginAfterDto(
                                        type: RobotLoginTypeConstants::LOGIN_OUT,
                                        robotId: $robotInfo['id'],
                                        remark: $remark
                                    )));
                                    //席位不足退出登录
                                    $this->loginOut(['id'=>$robotInfo['id']]);
                                }else{
                                    //席位不足退出登录
                                    $this->loginOutByServerId($serverId,$uuid);
                                }
                                throw new NormalStatusException($remark);
                            }
                            $seatId = $seat->id;
                        }else{
                            $seatId = $robotInfo->seat_id;
                        }

                        //更新席位使用状态
                        $this->seatMapper->update($seatId,['use_status' => StatusConstants::ENABLE]);
                        $corpWxid = $response['corp_id'];
                        if(empty($robotInfo)){
                            $robotData = [
                                'uid' => $params['uid'],
                                'main_uid' => $mainUid,
                                'nickname' => $response['nickname'],
                                'avatar' => $response['avatar'],
                                'user_id' => $response['user_id'],
                                'corp_wxid' => $corpWxid,
                                'robot_key' => $uuid,
                                'seat_id' => $seatId,
                                'server_id' => $serverId,
                                'first_login_time' => Carbon::now()->toDateTimeString(),
                                'login_time' => Carbon::now()->toDateTimeString(),
                                'login_status' => 1,
                                'pro_code' => $proCode,
                                'city_code' => $cityCode,
                                'pro_name' => $proName,
                                'city_name' => $cityName,
                                'server_pro_code' => $serverInfo->pro_code,
                                'server_city_code' => $serverInfo->city_code,
                                'server_pro_name' => $serverProName,
                                'server_city_name' => $serverCityName,
                                'is_yd' => $isYd,
                                'uuid' => $uuid
                            ];
                            $robotId = $this->robotMapper->save($robotData);

                            $this->serverService->increment($serverId);
                        }else{
                            $robotId = $robotInfo->id;
                            if($robotInfo['user_id'] != $response['user_id']){
                                $remark = '拟登录的企微号与实际扫码企微号不一致，请在手机上切换后重新扫码登录~';
                                $this->eventDispatcher->dispatch(new RobotLoginAfter(new RobotLoginAfterDto(
                                    type: RobotLoginTypeConstants::LOGIN_OUT,
                                    robotId: $robotId,
                                    remark: $remark
                                )));
                                throw new NormalStatusException($remark);
                            }

                            $updateData = [
                                'nickname' => $response['nickname'],
                                'avatar' => $response['avatar'],
                                'robot_key' => $uuid,
                                'seat_id' => $seatId,
                                'login_time' => Carbon::now()->toDateTimeString(),
                                'login_status' => 1,
                                'pro_code' => $proCode,
                                'city_code' => $cityCode,
                                'pro_name' => $proName,
                                'city_name' => $cityName,
                                'server_pro_code' => $serverInfo->pro_code,
                                'server_city_code' => $serverInfo->city_code,
                                'server_pro_name' => $serverProName,
                                'server_city_name' => $serverCityName,
                                'is_yd' => $isYd,
                                'uuid' => $uuid,
                                'deleted_at' => null
                            ];

                            if($robotInfo->server_id != $serverId){
                                $updateData['server_pro_code'] = $serverInfo->pro_code;
                                $updateData['server_city_code'] = $serverInfo->city_code;
                            }

                            if(!empty($robotInfo->deleted_at)){
                                $updateData['first_login_time'] = $updateData['login_time'];
                                $this->serverService->increment($serverId);
                            }

                            $this->robotMapper->model::query()
                                ->withTrashed()
                                ->where('id',$robotId)
                                ->update($updateData);
                        }

                        //检测其他地方登录的机器人
                        $loginElsewhereRobotId = $this->robotMapper->getLoginElsewhereRobotId($robotId,$response['user_id']);
                        if(!empty($loginElsewhereRobotId)){
                            $this->loginOut(['id'=>$loginElsewhereRobotId]);
                        }

                        $this->robotMapper->clearCache($robotId,$uuid);
                        $this->eventDispatcher->dispatch(new RobotLoginAfter(new RobotLoginAfterDto(
                            type: RobotLoginTypeConstants::LOGIN,
                            robotId: $robotId,
                            remark: '登录成功',
                        )));
                        redis()->del($checkKey);
                    }
                }
            }
            return $loginStatus;
        } catch (LockTimeoutException $e) {
            // 无法获取锁...
            return $loginStatus;
        } finally {
            optional($lock)->release();
        }
    }

    private function winRobotLogin(array $params)
    {
        $mainUid = $params['main_uid'];
        $lock = lock('robot_login_win_lock:'.$mainUid, 10);
        $loginStatus = 0;
        try {
            $lock->block(5);
            $loginData =  redis()->get("robot_login_result:".$params['loginQrcodeKey']);
            if(!empty($loginData)){
                $loginStatus = $loginData['login_qrcode_status'];
                $robotInfo = $this->robotMapper->model::query()
                    ->withTrashed()
                    ->where('main_uid',$mainUid)
                    ->where('user_id',$loginData['user_id'])
                    ->first();

                $customerParam = $loginData['customer_param'];
                $customerParamArr = explode('_',$customerParam);
                $serverId = $customerParamArr[1];//所在服务器ID
                $serverInfo = $this->serverService->findById($serverId);
                //所在省份编码
                $proCode = $customerParamArr[2] ?? '';
                //所在城市编码
                $cityCode = $customerParamArr[3] ?? '';

                $isYd = 0;
                if($serverInfo->pro_code != $proCode || $serverInfo->city_code != $cityCode){
                    $isYd = 1;
                }

                $regionCode = array_unique(array_filter([$serverInfo->pro_code,$serverInfo->city_code,$proCode,$cityCode]));
                $regionNameMap = Region::query()
                    ->whereIn('code',$regionCode)
                    ->pluck('name','code')
                    ->toArray();
                $proName = '';
                $cityName = '';
                if(!empty($proCode)){
                    $proName = $regionNameMap[$proCode] ?? '';
                }
                if(!empty($cityCode)){
                    $cityName = $regionNameMap[$cityCode] ?? '';
                }
                $serverProName = $regionNameMap[$serverInfo->pro_code] ?? '';
                $serverCityName = $regionNameMap[$serverInfo->city_code] ?? '';

                $robotKey = $loginData['key'];
                $corpWxid = $loginData['corp_id'];
                $uuid = $loginData['uuid'];

                if($loginStatus == 2){

                    if(empty($robotInfo) || empty($robotInfo->seat_id)){
                        //机器人登录成功
                        $seat = $this->getAvailableSeats($mainUid);
                        if(empty($seat)){
                            $remark = '账户席位不足，请购买席位后重试~';
                            if(!empty($robotInfo)){
                                $this->eventDispatcher->dispatch(new RobotLoginAfter(new RobotLoginAfterDto(
                                    type: RobotLoginTypeConstants::LOGIN_OUT,
                                    robotId: $robotInfo['id'],
                                    remark: $remark
                                )));
                                //席位不足退出登录
                                $this->loginOut(['id'=>$robotInfo['id']]);
                            }else{
                                //席位不足退出登录
                                $this->loginOutByServerId($serverId,$robotKey);
                            }
                            throw new NormalStatusException($remark);
                        }
                        $seatId = $seat->id;
                    }else{
                        $seatId = $robotInfo->seat_id;
                    }

                    //更新席位使用状态
                    $this->seatMapper->update($seatId,['use_status' => StatusConstants::ENABLE]);

                    if(empty($robotInfo)){
                        $robotData = [
                            'uid' => $params['uid'],
                            'main_uid' => $mainUid,
                            'nickname' => $loginData['nickname'],
                            'avatar' => $loginData['avatar_url'],
                            'user_id' => $loginData['user_id'],
                            'corp_wxid' => $corpWxid,
                            'robot_key' => $robotKey,
                            'seat_id' => $seatId,
                            'server_id' => $serverId,
                            'first_login_time' => Carbon::now()->toDateTimeString(),
                            'login_time' => Carbon::now()->toDateTimeString(),
                            'login_status' => 1,
                            'pro_code' => $proCode,
                            'city_code' => $cityCode,
                            'pro_name' => $proName,
                            'city_name' => $cityName,
                            'server_pro_code' => $serverInfo->pro_code,
                            'server_city_code' => $serverInfo->city_code,
                            'server_pro_name' => $serverProName,
                            'server_city_name' => $serverCityName,
                            'is_yd' => $isYd,
                            'uuid' => $uuid
                        ];
                        $robotId = $this->robotMapper->save($robotData);

                        $this->serverService->increment($serverId);
                    }else{
                        $robotId = $robotInfo->id;
                        if($robotInfo['user_id'] != $loginData['user_id']){
                            $remark = '拟登录的企微号与实际扫码企微号不一致，请在手机上切换后重新扫码登录~';
                            $this->eventDispatcher->dispatch(new RobotLoginAfter(new RobotLoginAfterDto(
                                type: RobotLoginTypeConstants::LOGIN_OUT,
                                robotId: $robotId,
                                remark: $remark
                            )));
                            throw new NormalStatusException($remark);
                        }

                        $updateData = [
                            'nickname' => $loginData['nickname'],
                            'avatar' => $loginData['avatar_url'],
                            'robot_key' => $robotKey,
                            'seat_id' => $seatId,
                            'login_time' => Carbon::now()->toDateTimeString(),
                            'login_status' => 1,
                            'pro_code' => $proCode,
                            'city_code' => $cityCode,
                            'pro_name' => $proName,
                            'city_name' => $cityName,
                            'server_pro_code' => $serverInfo->pro_code,
                            'server_city_code' => $serverInfo->city_code,
                            'server_pro_name' => $serverProName,
                            'server_city_name' => $serverCityName,
                            'is_yd' => $isYd,
                            'uuid' => $uuid,
                            'deleted_at' => null
                        ];

                        if($robotInfo->server_id != $serverId){
                            $updateData['server_pro_code'] = $serverInfo->pro_code;
                            $updateData['server_city_code'] = $serverInfo->city_code;
                        }

                        if(!empty($robotInfo->deleted_at)){
                            $updateData['first_login_time'] = $updateData['login_time'];
                            $this->serverService->increment($serverId);
                        }

                        $this->robotMapper->model::query()
                            ->withTrashed()
                            ->where('id',$robotId)
                            ->update($updateData);
                    }

                    //检测其他地方登录的机器人
                    $loginElsewhereRobotId = $this->robotMapper->getLoginElsewhereRobotId($robotId,$loginData['user_id']);
                    if(!empty($loginElsewhereRobotId)){
                        $this->loginOut(['id'=>$loginElsewhereRobotId]);
                    }

                    $this->robotMapper->clearCache($robotId,$robotKey);
                    $this->eventDispatcher->dispatch(new RobotLoginAfter(new RobotLoginAfterDto(
                        type: RobotLoginTypeConstants::LOGIN,
                        robotId: $robotId,
                        remark: '登录成功',
                    )));
                }
            }
            return $loginStatus;
        } catch (LockTimeoutException $e) {
            // 无法获取锁...
            return $loginStatus;
        } finally {
            optional($lock)->release();
        }
    }

    public function robotLoginStatus(array $params): void
    {
        $list = $this->robotMapper->model::query()
            ->select(['id','seat_id','robot_key','server_id'])
            ->where('uid',$params['uid'])
            ->where('login_status',StatusConstants::ENABLE)
            ->get();

        foreach ($list as $robot){
            $robotApiService = make(RobotApiService::class, [$robot->server_id, $robot->robot_key]);
            $result = $robotApiService->getLoginStatus();
            if($result === false || $result['user_online_status'] != 2){
                //登录已过期
                $this->loginOutNotify($robot);
            }
        }

    }

    /**
     * @param $serverId
     * @param $robotKey
     * @return void
     */
    private function loginOutByServerId($serverId,$uuid): void
    {
        make(Robot::class,[$serverId,$uuid])->gateway()
            ->loginOut();
    }

    /**
     * 机器人登录（二次登录）
     * @param array $params
     * @return bool
     */
    public function autoLogin(array $params): bool
    {
        $mainUid = $params['main_uid'];
        $robotInfo = $this->robotMapper->findById($params['id']);
        if (empty($robotInfo)) {
            return false;
        }

        if(empty($robotInfo->uuid)){
            throw new NormalStatusException("登录失败，请点击扫码登录登录进行扫码登录");
        }

        $lock = lock('robot_auto_login_lock'.$params['main_uid'],  4);
        try {
            $lock->block(3);

            if(empty($robotInfo->seat_id)){
                //获取可用席位
                $seat = $this->getAvailableSeats($mainUid);
                if(empty($seat)){
                    throw new NormalStatusException("无可用座席");
                }
            }

            //机器人登录
            $robotApiService = make(Robot::class,[$robotInfo->server_id,$robotInfo->uuid])->gateway();
//            $proxyUrl = '';
//            if($robotInfo->is_yd){
//                $proxyUrl = container()->get(ProxyIpInterface::class)->getShortProxyIp($robotInfo->pro_code,$robotInfo->city_code);
//            }

            $loginResult = $robotApiService->manualLogin($robotInfo->user_id,'');
            if($loginResult === false){
                $this->loginOutNotify($robotInfo);
                throw new NormalStatusException("登录失败，请点击扫码登录登录进行扫码登录");
            }
//            //更新机器人席位
            if(empty($robotInfo->seat_id)){
                $this->updateRobotSeat($robotInfo->id,$seat->id);
            }
            $this->eventDispatcher->dispatch(new RobotLoginAfter(new RobotLoginAfterDto(
                type: RobotLoginTypeConstants::LOGIN,
                robotId: $robotInfo['id'],
                remark: '登录成功'
            )));
            return true;
        } catch (LockTimeoutException $e) {
            // 无法获取锁...
            throw new NormalStatusException("登录中");
        }catch (NormalStatusException $e){
            $this->eventDispatcher->dispatch(new RobotLoginAfter(new RobotLoginAfterDto(
                type: RobotLoginTypeConstants::LOGIN_OUT,
                robotId: $robotInfo['id'],
                remark: $e->getMessage()
            )));
            throw new NormalStatusException($e->getMessage());
        } finally {
            optional($lock)->release();
        }
    }

    /**
     * 登录成功
     * @param ChRobot $robotInfo
     * @param string $clientKey
     * @return void
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function loginSuccess(ChRobot $robotInfo,string $uuid): void
    {
        if(empty($robotInfo)){
            return;
        }
        $isFirstLogin = $robotInfo->login_time == $robotInfo->first_login_time;
        logger()->info('登录成功通知',[
            'robot_id' => $robotInfo->id,
            'is_first_login' => $isFirstLogin,
        ]);

        if($isFirstLogin){
            //延迟同步用户和群聊信息
            container()->get(LowQueueService::class)->push(new CommonJob(new CommonJobDto(
                classname: RobotLoginService::class,
                method: 'syncContact',
                data:[
                    'robot_id' => $robotInfo->id
                ]
            )),3 * 60);

            container()->get(LowQueueService::class)->push(new CommonJob(new CommonJobDto(
                classname: RobotLoginService::class,
                method: 'syncRoom',
                data:[
                    'robot_id' => $robotInfo->id
                ]
            )),5 * 60);
        }

        if(empty($robotInfo->userid)){
            container()->get(LowQueueService::class)
                ->push(new UserIdToOpenIdTaskJob(
                    $robotInfo->id,
                    $robotInfo->user_id
                ),3);
        }

        if(empty($robotInfo->avatar)){
            //更新用户头像
            event(new RobotInfoChange($robotInfo));
        }

        $updateData = [
            'login_status' => 1,
        ];

        //更新设备ID
        if($robotInfo->uuid != $uuid){
            $updateData['uuid'] = $uuid;
        }

        if($robotInfo->login_status == 0){
            $updateData['login_time'] = Carbon::now()->toDateTimeString();
//            //查询当前机器人登录的席位
//            if(empty($robotInfo->seat_id)){
//                $lock = lock('robot_seat_lock'.$robotInfo->main_uid, 4);
//                try {
//                    $lock->block(2);
//                    $seat = $this->getAvailableSeats($robotInfo->main_uid);
//                    if(empty($seat)){
//                        //没有可用席位，机器人退出登录
//                        $this->loginOut(['id'=>$robotInfo->id]);
//                        return;
//                    }
//                    $this->updateRobotSeat($robotInfo->id,$seat->id);
//                }catch (LockTimeoutException $e){
//                    return;
//                } finally {
//                    optional($lock)->release();
//                }
//            }
            //取消代理
            $apiService = make(Robot::class,[$robotInfo->server_id,$robotInfo->uuid])->gateway();
            $apiService->cancelProxy();
        }

        $this->robotMapper->update($robotInfo->id,$updateData);
        $this->robotMapper->clearCache($robotInfo->id,$uuid);
    }

    /**
     * 首次登录同步用户
     * @param array $data
     * @return void
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function syncContact(array $data): void
    {
        $robotId = $data['robot_id'];
        //同步用户
        container()->get(ChContactService::class)->addSyncTask($robotId);
    }

    /**
     * 首次登录同步群聊
     * @param array $data
     * @return void
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function syncRoom(array $data): void
    {
        $robotId = $data['robot_id'];
        //同步群聊
        container()->get(ChRoomService::class)->addSyncTask($robotId);
    }

    /**
     * 退出登录
     * @param array $params
     * @return void
     */
    public function loginOut(array $params): void
    {
        $robotInfo = $this->robotMapper->findById($params['id']);
        if(empty($robotInfo)){
            throw new NormalStatusException('请选择企微号');
        }

        $service = make(Robot::class,[$robotInfo->server_id,$robotInfo->uuid])->gateway();

        $response = $service->loginOut();
//        if($response === false){
//            throw new NormalStatusException($service->getErrorMsg());
//        }
        $this->loginOutNotify($robotInfo);
    }

    /**
     * 退出登录通知
     * @param ChRobot|null $robotInfo
     * @return void
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws \RedisException
     */
    #[Transaction]
    public function loginOutNotify(?ChRobot $robotInfo):void
    {
        if(!empty($robotInfo) && $robotInfo->login_status == 1){
            $lock = lock('robot_login_out_lock'.$robotInfo->id, 4);
            try {
                $lock->block(2);
//                if(!empty($robotInfo->seat_id)){
//                    //更新席位使用状态
//                    $this->seatMapper->update($robotInfo->seat_id,[
//                        'use_status' => StatusConstants::DISABLE
//                    ]);
//                }

                $updateData = [
                    'login_status' => 0
//                    'seat_id' => 0
                ];

                if($robotInfo->login_status == 1){
                    $updateData['login_out_time'] = Carbon::now()->toDateTimeString();
                }

                //更新机器人状态
                ChRobot::query()
                    ->withTrashed()
                    ->where('id',$robotInfo->id)
                    ->update($updateData);

                $this->robotMapper->clearCache($robotInfo['id'],$robotInfo->robot_key);
                $this->eventDispatcher->dispatch(new RobotLoginAfter(new RobotLoginAfterDto(
                    type: RobotLoginTypeConstants::LOGIN_OUT,
                    robotId: $robotInfo['id'],
                    remark: '退出登录'
                )));
            }catch (LockTimeoutException $e){
            } finally {
                optional($lock)->release();
            }
        }
    }

    /**
     * 获取可用的座席
     * @param int $mainUid
     * @return MineModel|ChSeat|Model|Builder|null
     */
    private function getAvailableSeats(int $mainUid): MineModel|ChSeat|Model|Builder|null
    {
        return $this->seatMapper->getAvailableSeats($mainUid);
    }

    /**
     * 更新机器人席位
     * @param int $robotId
     * @param int $seatId
     * @return void
     */
    public function updateRobotSeat(int $robotId,int $seatId): void
    {
        $this->robotMapper->update($robotId,['seat_id' => $seatId,'login_status' => 1]);
        $this->seatMapper->update($seatId,['use_status' => StatusConstants::ENABLE]);
    }
}